﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using PHMEE.DTOS.BaseSys;
using PHMEE.ToolKits;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.Auditing;
using Volo.Abp.Identity.AspNetCore;
using Volo.Abp.Users;

namespace PHMEE
{
    public class AuthAppService : PHMEEAppService, IAuthAppService
    {
        private readonly HttpClient httpClient;
        private readonly IHttpClientFactory httpClientFactory;
        private readonly AbpSignInManager abpSignInManager;
        private readonly IConfiguration configuration;
        private readonly IVesselRepository vesselRepository;
        private readonly ICompanyRepository companyRepository;
        private readonly IFleetRepository fleetRepository;
        private readonly IAccountAppService accountAppService;

        public AuthAppService(IHttpClientFactory httpClientFactory, AbpSignInManager abpSignInManager, IConfiguration configuration, IVesselRepository vesselRepository, ICompanyRepository companyRepository, IFleetRepository fleetRepository)
        {
            this.httpClientFactory = httpClientFactory;
            this.abpSignInManager = abpSignInManager;
            this.configuration = configuration;
            this.vesselRepository = vesselRepository;
            this.companyRepository = companyRepository;
            this.fleetRepository = fleetRepository;
            httpClient = httpClientFactory.CreateClient();
            httpClient.BaseAddress = new Uri(configuration["AuthServer:Authority"]);
        }

        public async Task<UserResultDto> Login(UserLoginDto model)
        {
            var result = await abpSignInManager.PasswordSignInAsync(model.username, model.password, true, true);

            if (result.IsNotAllowed)
            {
                throw new UserFriendlyException("The account has been disabled!");
            }

            if (!result.Succeeded)
            {
                throw new UserFriendlyException("Incorrect username or password!");
            }
            else if (result.IsLockedOut)
            {
                throw new UserFriendlyException("Login failed, the account is locked!");
            }

            var tokenRequest = PHMEECoreHelper.GetDerivedProperties(model, true).ToDictionary(item => item.Key, item => item.Value?.ToString());
            var response = await httpClient.PostAsync("connect/token", new FormUrlEncodedContent(tokenRequest));
            if (!response.IsSuccessStatusCode)
            {
                throw new UserFriendlyException("Your session has expired, please log in again!");
            }
            var responseContent = await response.Content.ReadAsStringAsync();

            var tokenResponse = PHMEECoreHelper.Deserialize<OpeniddictToken>(responseContent);

            var resultDto = new UserResultDto()
            {
                Success = true,
                Data = new UserResult
                {
                    UserName = CurrentUser.UserName,
                    NickName = $"{CurrentUser.SurName}{CurrentUser.Name}",
                    Roles = CurrentUser.Roles?.ToList(),
                    AccessToken = tokenResponse.access_token,
                    RefreshToken = tokenResponse.refresh_token,
                    Expires = tokenResponse.expires_in
                }
            };

            return resultDto;
        }

        public async Task<UserResultDto> RefreshToken(UserRefreshDto model)
        {
            var tokenRequest = PHMEECoreHelper.GetDerivedProperties(model, true).ToDictionary(item => item.Key, item => item.Value?.ToString());
            var response = await httpClient.PostAsync("connect/token", new FormUrlEncodedContent(tokenRequest));
            if (!response.IsSuccessStatusCode)
            {
                throw new UserFriendlyException("Your session has expired, please log in again!");
            }
            var responseContent = await response.Content.ReadAsStringAsync();

            var tokenResponse = PHMEECoreHelper.Deserialize<OpeniddictToken>(responseContent);

            var resultDto = new UserResultDto()
            {
                Success = true,
                Data = new UserResult
                {
                    UserName = CurrentUser.UserName,
                    NickName = $"{CurrentUser.SurName}{CurrentUser.Name}",
                    Roles = CurrentUser.Roles?.ToList(),
                    AccessToken = tokenResponse.access_token,
                    RefreshToken = tokenResponse.refresh_token,
                    Expires = tokenResponse.expires_in
                }
            };

            return resultDto;
        }

        public async Task<VesselInitialDto> GetInitialVessel(VesselInitialInput input)
        {
            VesselInitialDto model = new VesselInitialDto();

            var query = await vesselRepository.PhmeeGetQuery();

            if (input.UserFilter)
            {
                var queryCompany = await companyRepository.PhmeeGetQuery();

                var companies = await AsyncExecuter.ToListAsync(queryCompany);

                companies = companies.WhereIf(CurrentUser.Id != null, item => item.UserIds.Contains(CurrentUser.Id.Value)).ToList();

                if (companies.Count <= 0)
                {
                    throw new UserFriendlyException($"尊敬的用户：{CurrentUser.UserName} 您好，系统检测到您尚未配置公司用户权限，请联系管理员进行配置后再重试！");
                }

                var companyIds = companies.Select(item => item.Id).ToList();

                var queryFleet = await fleetRepository.PhmeeGetQuery();

                var fleetIds = queryFleet.Where(item => companyIds.Contains(item.CompanyId)).Select(item => item.Id).ToList();

                query = query.Where(item => fleetIds.Contains(item.FleetId));

            }

            query = query.OrderByDescending(item => item.CreationTime);

            Vessel vessel = query.FirstOrDefault();

            if (vessel != null)
            {

                model.VesselId = vessel.Id;

                model.VesselName = vessel.NameEn;

            }

            return model;

        }
    }
}
